
/******************************************************************************
*
* File: Application.c
*
* Title:    Shacker Interface (c) 
* Authors:  Andrew Ware, Robert Pyke, Geoff Willson, Michael Peever, Erin Daley
*
* Description:  This program is used in conjunction with a Graphical user interface 
*               to operate a shaker table. It's purpose is to  simulate helicopter 
*               vibrations for investigation into the effects these vibrations have 
*               on decompression sickness patients during emergency flights.
*               (simulation only!!) for full functionality teh adittion of ADC inputs
*               and DAC outputs are required
*
* Documentation:
*
* Include Files: mqx.h
*                bsp.h
*                main.h
*                usb_logger.h
*                Application.h
*
* Assembler: Freescale CodeWarior 6.3 using MQX 3.8 RTOS
* Flash Programer: Cold Fire V2-V4 JM60 OSBDM
*
* Revision History:
*
* Rev #     Date      Who            Comments
* -----  -----------  ------         -------------------------------------
* V3.5   17/10/2012   Andrew Ware
******************************************************************************/
#include <mqx.h>
#include <bsp.h>
#include "main.h"
#include <usb_logger.h>
#include <Application.h>

/*******************************************************************************
 *
 * Constants
 *
 ******************************************************************************/
 #define MY_TRIGGER_0 ADC_TRIGGER_1
 #define MY_TRIGGER_1 ADC_TRIGGER_2

/*******************************************************************************
 *
 *  Global Variables
 *
 *******************************************************************************/
  uint_16 InRing        [6000];     // 6K butes of RAM reserved for In Ring Buffer
  uint_16 OutRing       [12000];    // 12K bytes of RAM reserved for Out Ring Buffer
  uint_16 InPutter      = 0;        // InBuffer putter
  uint_16 InGetter      = 0;        // InBuffer getter
  uint_16 OutPutter     = 0;        // OutBuffer putter
  uint_16 OutGetter     = 0;        // OutBuffer getter
  uint_8 StatusData       [10];     // Data status and error vector
  uint_8 LEDStat        = 0x00;     // LED Status
  uint_16 RunFlag       = 0x0000;   // Controls transfer between in and out buffers
  uint_32 Data_Length   = 0;
  uint_16 InError       = 0;        // Registers no of Rx index errors
  
 /*****************************************************************************
 *
 *  Initializations
 *
 *****************************************************************************/
 
  //    Control structures for EP3 OUT (receive) packet transactions.
  //    These are declared in usb_logger.c
  
 extern EP_RX_CTRL ep1_rx_ctrl;
 extern EP_RX_CTRL ep3_rx_ctrl;
 
 // Logger Global Variable Structure. 
 extern LOGGER_GLOBAL_VARIABLE_STRUCT g_logger;

 
 // Handles for operating the LEDs LED(1:2),SW(1:2)
  
 FILE_PTR led_file1, led_file2, led_file3, result_file; 
 
 // LED Arrays 
 
 // Define an array listing all the LEDs, USed for opening GPIO drivers
 GPIO_PIN_STRUCT pins1[] = 
 {
    /* Open file to control LEDs(1-4) and initialise their status to OFF.
        Here <additional_flags> = GPIO_PIN_STATUS_0 will clear the pin. */
    BSP_LED1 | GPIO_PIN_STATUS_0,   // 
    BSP_LED2 | GPIO_PIN_STATUS_0,
    BSP_LED3 | GPIO_PIN_STATUS_0,
    BSP_LED4 | GPIO_PIN_STATUS_0,
    GPIO_LIST_END
 };
 
 /* Define arrays for writing to the LEDs individually.
    These are used with the Generic IOCTL Commands. */
 
 // For controlling LED1 individually 
  GPIO_PIN_STRUCT pins2[] = 
 {
    BSP_LED1,
    GPIO_LIST_END
 };
 // For controlling LED2 individually 
  GPIO_PIN_STRUCT pins3[] = 
 {
    BSP_LED2,
    GPIO_LIST_END
 };
 // For controlling LED3 individually 
  GPIO_PIN_STRUCT pins4[] = 
 {
    BSP_LED3,
    GPIO_LIST_END
 };
 // For controlling LED4 individually 
  GPIO_PIN_STRUCT pins5[] = 
 {
    BSP_LED4,
    GPIO_LIST_END
 };
 
/******************************************************************************
 *
 * Function Name  : App_Init
 * Returned Value : None
 *
 * Operation      : Runs individual initialisation functions for USB_Logger, 
 *                  endpoints 3 & 4, Leds 1-4 & 2KHz interrupt. Updates LED 
 *                  status depending LEDStat varianle controlled by GUI. 
 *                  Contains 1 ms delay between polling EP3 for incoming 
 *                  command/Data from GUI.
 *
 /****************************************************************************/
void App_Init(void)
{           
    // Initialise USB structure
    USB_Class_LOGGER_Init();

    // Initialise endoint control structure
    Endpoint_Init();

    // Initialise LEDS 1-4 control
    LED_1_4_Init();

    // Initialise 2 KHz ISR
    TwoKHz_Interrupt_Init();

    // Infinite Loop 
    while (TRUE)
    {
        switch(LEDStat)
        {
            case 0xFF:
            LEDSON();
            break;

            case 0x00:
            LEDSOFF();
            break;
        }
        // 1 milli sec delay
        _time_delay(1);
    }
}

/****************************************************************************
 *
 * Function Name  : Endpoint_Init
 * Returned Value : None
 *
 * Operation      : Initialises the structures for controlling 
 *                  endpoint transactions.
 *                  Structures store data packets received at OUT endpoints.
 *
 /***************************************************************************/
 void Endpoint_Init(void)
 {  
    EP_RX_CTRL_PTR epctrlPtr;       // Pointer to an EP control structure
    
    // Initialise EP1 structure 
    epctrlPtr = &ep1_rx_ctrl;       // Set the pointer to the EP1 control structure
    epctrlPtr->pkt_rec = FALSE;     // Clear packet received flag
    epctrlPtr->overrun_err = FALSE; // Clear overrun error flag
    epctrlPtr->len = 0x00;          // Received packet length zero
    
    // Initialise EP3 structure 
    epctrlPtr = &ep3_rx_ctrl;       // Set the pointer to the EP3 control structure
    epctrlPtr->pkt_rec = FALSE;     // Clear packet received flag
    epctrlPtr->overrun_err = FALSE; // Clear overrun error flag
    epctrlPtr->len = 0x00;          // Received packet length zero
 }
 
 /****************************************************************************
 *
 * Function Name  : LED_1_4_Init
 * Returned Value : None
 *
 *  Operation:      Open a GPIO device for writing to the LEDs.
 *                  Specify the pins to be used (BSP_LED1:BSP_LED4)
 *                  and the pin direction (OUT - write).
 *                  Open a GPIO device for reading the switches SW1 & SW2.
 *                  Specify the pins to be used (BSP_BUTTON1, BSP_BUTTON2)
 *                  and the pin direction (IN - read).
 *                  Each open operation returns a handle to the GPIO device.
 *
 /***************************************************************************/
 void LED_1_4_Init()
 {
    // Open a GPIO device for writing & readubg to & from the LEDs
    led_file1 = fopen("gpio:write", (char_ptr) &pins1);
    led_file2 = fopen("gpio:read", (char_ptr) &pins1);
 }
 
 /****************************************************************************
 *
 * Function Name  : 2KHz_Interrupt_Init
 * Returned Value : None
 *
 * Operation      : Using the M52259 bus clock (80MHz) and modulas of 40K to create 
 *                  Interrupt at 2KHz rate. Vector connection: "TwoKHz_ISR"
 *
 /***************************************************************************/
 void TwoKHz_Interrupt_Init(void)
{
    // Set a pointer to the Internal Peripheral System base address
    VMCF5225_STRUCT_PTR reg_ptr = (VMCF5225_STRUCT_PTR)BSP_IPSBAR;
    // Set the mode register DTMR0.
    reg_ptr->DMA_TIMER[0].DTMR = 0x0019U;   // PE=0: Prescale = 0.
                                            // CE=0: Disable capture event output.Timer in reference mode.
                                            // OM=0: Active-low pulse for one internal bus clock cycle.
                                            // ORRI=1: Enable DMA request or interrupt upon reaching the
                                            //          reference value.
                                            // FRR=1: Timer count is reset immediately after reaching the 
                                            //          reference value.
                                            // CLK=0: Stop count.
                                            // RST=1: Enable timer.
    
    // Set the DMA Timer Extended Mode Register
    reg_ptr->DMA_TIMER[0].DTXTMR = 0x00U;   // DMAEN=0: DMA request disabled.
                                            // HALTED=0: Timer function not affected by core hault.
                                            // MODE16=0: Timer increment = 1.
                                            
    // Clear the Output reference Interrupt flag
    reg_ptr->DMA_TIMER[0].DTER = 0x02U;     
    // Set modulus to 40,000 for 2kHz periodic interrupt, 80MHz/2kHz = 40,000.
    // reg_ptr->DMA_TIMER[0].DTRR = 0x00009C40; // 2KHz  - Desired speed
    reg_ptr->DMA_TIMER[0].DTRR = 0x0000D055; // 1.5KHz  - (Slowed Speed)
    
    // Reset counter
    reg_ptr->DMA_TIMER[0].DTCN = 0x00UL;    
    // Start the counter
    reg_ptr->DMA_TIMER[0].DTMR = 0x001BU;   
    
    /* Configure the DMA Timer Channel 0 Interrupt */
    // Set the Interrupt Priority & level
    reg_ptr->ICTRL0.ICR[19] = 0x23;         // Interrupt Level: 4, Priority: 3
    // Clear the interrupt mask flag.   
    reg_ptr->ICTRL0.ICTRL.IMRL &= ~MCF52XX_ICTR_IMRL_INT_MASK19;    // Unmask DMA Timer 0 interrupt   
                      
    /* ISR vector table conection*/
    _int_install_isr(MCF5225_INT_DTIM0, (void (_CODE_PTR_)(pointer))TwoKHz_ISR,NULL);
}

/****************************************************************************
 *
 *  Functions
 *
 ****************************************************************************/

/****************************************************************************
 *
 * Function Name  : LEDSOFF, LEDSON 
 * Returned Value : None
 *
 * Operation      : Calling function modifies which LEDs are on and off.
 *
 /***************************************************************************/
void LEDSOFF(void)  // All LEDS off
{
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG0, &pins2);
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG0, &pins3);
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG0, &pins4);
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG0, &pins5);
}
void LEDSON(void)   // All LEDS on
{
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins2);
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins3);
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins4);
        ioctl(led_file1, GPIO_IOCTL_WRITE_LOG1, &pins5);
}

/****************************************************************************
 *
 * Function Name  : EP3_PACKET_REC()
 * Returned Value : None
 *
 * Operation      : Checks for the arrival of a packet at EP3
 *                  and processes received packets.
 *                  The ep3_rx_ctrl structure (declared in
 *                  usb_logger.c) are used for controlling packet reception.
 *                  The arrival of a packet is indicated 
 *                  by the flag epn_rx_ctrl.pkt_rec.
 *                  Received packets are transferred to the 
 *                  receive packet buffer epn_rx_ctrl.ep_pkt_buf[].
 *                  The size of a received packet is indicated by epn_rx_ctrl.len.
 *                  First byte recieved is a commmand, second byte is the
 *                  amount of data being trasfered. 
 *                  If Tx command is recieved, the following byte is amount of 
 *                  bytes to be Tx. See Application.h for command list. 
 *                  All data is recieved as 8bit bytes and then looped into InBuffer 
 *                  as 16bit bytes where two 8bit bytes are combined to form the 
 *                  one 16bit byte. case statemant is used to differntiate between 
 *                  different commands.
 *
 /***************************************************************************/
 void EP3_PACKET_REC(void)
 {
    uint_32 i;
    uint_32 j;
    uint_32  k;
    uint_16 temp1;
    uint_16 temp2;
    uint_8  InIndex;                // Recieed data index used for Rx error check       
    uint_8 command;
    uint_32 TxSize;     
    EP_RX_CTRL_PTR ep3ctrlPtr;      // Pointer for EP3 control structure
    ep3ctrlPtr = &ep3_rx_ctrl;      // Set the pointer to the EP3 control structure
    
    // Check for EP3 received packet
    if(ep3ctrlPtr->pkt_rec == TRUE) 
    {
        // EP3 packet has arrived 
        // Transfer the packet to the EP3 receive packet buffer ep_pht_buf[].
        for(i = 0; i < ep3ctrlPtr->len; i++)
        {
            ep3ctrlPtr->ep_pkt_buf[i] = *ep3ctrlPtr->buffer_ptr++;
        }
        
        //  Clear packet received flag 
        ep3ctrlPtr->pkt_rec = FALSE;
        
        // Not using overrun error at the moment
        // Check for an overrun error 
        if(ep3ctrlPtr->overrun_err == TRUE)
        {
            ep3ctrlPtr->overrun_err = FALSE;
        }

        // Process EP3 command: 
        // Command is the first byte 
        // Size of data request is second byte
        command = ep3ctrlPtr->ep_pkt_buf[0];

        switch(command)
        {   
            case Rx_Data:   
            // Recieve data via EP3
            // Data_Length = ep3ctrlPtr->len;
            Data_Length = ep3ctrlPtr->ep_pkt_buf[1];
            k = 0;  
            InIndex = 0;
            // Loop EP3 in Buffer into In ring buffer
            for(i = 2; i <  Data_Length + 2; i+=2)  
                {   
                    // Convert 2 8bit bytes too 1 16bit byte.
                    temp1 = 0;
                    temp1 = ep3ctrlPtr->ep_pkt_buf[i];
                    temp1 = temp1<<8;
                    InRing[InPutter] = temp1;
                    temp2 = ep3ctrlPtr->ep_pkt_buf[i+1];    
                    temp2 &= 0x00FF;    
                    InRing[InPutter] += temp2;  

                    // Check index increments correctly, First & every 3rd byte of buffer
                    if(k%3==0)
                    {
                        InIndex++;  
                        if(InRing[InPutter] != InIndex) // Check if index error 
                        {
                            InError++;                  // Increment InError counter
                        }
                        InIndex = InRing[InPutter];     // Set last index as new
                    }
                    k++; 

                    InPutter++;             // increment inbuffer putter
                    if(InPutter > 5999)     // End of buffer check 
                    {
                        InPutter = 0;       // Return to start
                    }
                }   
            break;  

            case Tx_Data:
            // Transmit data via EP3
            TxSize = ep3ctrlPtr->ep_pkt_buf[1];

            // Loop Out ring buffer into EP3 Out Buffer 
            // Convert from 1 16bit byte to 2 8bit bytes
                for(i=0; i<TxSize; i+=2)
                {
                    temp1 = 0;
                    temp1 = OutRing[OutGetter]; 
                    temp2 = temp1 & 0xFF00;
                    temp2 = temp2>>8;
                    g_logger.rpt_buf[i] = temp2;

                    temp1 &= 0x00FF;
                    g_logger.rpt_buf[i+1] = temp1;

                    OutGetter++;                
                    if(OutGetter > 11999)       // End of buffer check
                    {
                        OutGetter = 0;          // End of buffer check
                    }
                }
            // Tx daata                 
            (void)USB_Class_EP4_Send_Data(USB_EP4, g_logger.rpt_buf,TxSize); 
            break;
            // USB connected    
            case USBCon:        // USB connected
            LEDStat = 0xFF;     // Set LEDS to on mode
            break;
            // USB disconnected 
            case USBDis:        // USB disconnected
            LEDStat = 0x00;     // Set LEDS to off mode
            break;
            // Run shaker table
            case Run:
            RunFlag = 0xFFFF;   // Start shakers (data transfer between in & out buffers)
            LEDStat = 0xF0;     // Set LEDS to Chase mode
            break;
            // Stop Shaker Table
            case Stop:          
            RunFlag = 0x00;     // Stop shakers 
            LEDStat = 0xFF;     // Set LEDS to on mode
            break;
            // reset all buffers and pointers
            case Reset:         
            RunFlag = 0x00;     // Lower run flag
            InPutter = 0;       // Reset buffer putters and getters
            InGetter = 0;
            OutPutter = 0;
            OutGetter = 0;
            InError = 0;
            for(j=0; j<6000; j++)   // Reset In Buffer data
            {
                InRing[j] = 0;
            }   
            for(j=0; j<12000; j++)  // Reset out Buffer data
            {
                OutRing[j] = 0;
            }   
            break;

            // Check buffer capacities and errors and Tx via EP4
            case Status:    
            // In Putter value
            temp1 = 0;
            temp1 = InPutter; 
            temp2 = temp1 & 0xFF00;
            temp2 = temp2>>8;
            g_logger.rpt_buf[0] = temp2;        
            temp1 &= 0x00FF;
            g_logger.rpt_buf[1] = temp1;

            // In Getter value
            temp1 = 0;
            temp1 = InGetter; 
            temp2 = temp1 & 0xFF00;
            temp2 = temp2>>8;
            g_logger.rpt_buf[2] = temp2;        
            temp1 &= 0x00FF;
            g_logger.rpt_buf[3] = temp1;

            //  Out putter value
            temp1 = 0;
            temp1 = OutPutter; 
            temp2 = temp1 & 0xFF00;
            temp2 = temp2>>8;
            g_logger.rpt_buf[4] = temp2;        
            temp1 &= 0x00FF;
            g_logger.rpt_buf[5] = temp1;

            // Out getter value
            temp1 = 0;
            temp1 = OutGetter; 
            temp2 = temp1 & 0xFF00;
            temp2 = temp2>>8;
            g_logger.rpt_buf[6] = temp2;        
            temp1 &= 0x00FF;
            g_logger.rpt_buf[7] = temp1;

            // Rx index error count
            temp1 = 0;
            temp1 = InError;
            temp2 = temp1 & 0xFF00;
            temp2 = temp2>>8;
            g_logger.rpt_buf[8] = temp2;        
            temp1 &= 0x00FF;
            g_logger.rpt_buf[9] = temp1; 

            // RunFlag Status
            if(RunFlag)
            {
                g_logger.rpt_buf[10] = 0xFF;    
                g_logger.rpt_buf[11] = 0xFF;    
            }
            else 
            {
                g_logger.rpt_buf[10] = 0x00;    
                g_logger.rpt_buf[11] = 0x00;    
            }

            // Tx via EP4
            (void)USB_Class_EP4_Send_Data(USB_EP4, g_logger.rpt_buf,12); 
            // Reset Error Index
            InError = 0;
            break;
        }
    }
 }

/****************************************************************************
*
* Interrupt Service Rutines
*
****************************************************************************/

/****************************************************************************
 *
 * Function Name  : 2KHZ_RealTime_ISR
 * Returned Value : None
 *
 * Operation      : Simulates the operation of the 2 shakers and 
 *                  3 accelermoters. Takes the index, Ch1 and Ch2 bytes of the 
 *                  3 byte data sequance and moves them directly from InBuffer
 *                  to OoutBuffer. To simulate the shaker and feedback hardware 
 *                  system charecteristic, Ch1 and ch2 data is used to create 
 *                  3 acceleromoter data sets which is added to the end of the 
 *                  end of the sequance. This is done utilising coefficients
 *                  A and B stored as constants ten times their value. Data
 *                  is stored in OutBUffer as 16Bit in following sequance: 
 *                  Index, shaker 1, shaker 2, ac1c 1, accl 2, accl 3.
 *                  Gettera and putters are checked after any increment for 
 *                  end of ring buffer role around. 
 *
 /***************************************************************************/
void TwoKHz_ISR(void)
{
	
    const int A  = 8;       // Error coefficent A X 10
    const int B  = 6;       // Error coefficent B X 10
    uint_16  Ch1 = 0;
    uint_16  Ch2 = 0;

	// Set a pointer to the Internal Peripheral System base address 
    VMCF5225_STRUCT_PTR reg_ptr = (VMCF5225_STRUCT_PTR)BSP_IPSBAR;
    // Clear the Output reference (Interrupt) event flag
    reg_ptr->DMA_TIMER[0].DTER = 0x02U; 
    // Check for end of data in InBuffer and auto stop if needed.
    if(InGetter==InPutter)
    {
        RunFlag=0;
    }
            
    // Transfer data from InBuffer to out OutBuffer simulating shaker table
    if(RunFlag)
    {
        // Index value
        OutRing[OutPutter] = InRing[InGetter];
        OutPutter++;
        InGetter++;
        if(InGetter>5999)
            {
                InGetter = 0;
            }
        if(OutPutter>11999)
            {
                OutPutter = 0;
            }
        // Channel 1
        Ch1 = InRing[InGetter];
        OutRing[OutPutter] = Ch1;
        OutPutter++;
        InGetter++;
        if(InGetter>5999)
            {
                InGetter = 0;
            }
        if(OutPutter>11999)
            {
                OutPutter = 0;
            }
        // Channel 2
        Ch2 = InRing[InGetter];
        OutRing[OutPutter] = Ch2;
        OutPutter++;
        InGetter++;
        if(InGetter>5999)
            {
                InGetter = 0;
            }
        if(OutPutter>11999)
            {
                OutPutter = 0;
            }
        // Accelerometer 1  
        OutRing[OutPutter] = (Ch1*A)/10;
        OutPutter++;
        if(OutPutter>11999)
            {
                OutPutter = 0;
            }
        // Accelerometer 2
        OutRing[OutPutter] = (((Ch1*A)/10)+((Ch2*B)/10))/2;
        OutPutter++;
        if(OutPutter>11999)
            {
                OutPutter = 0;
            }
        // Accelerometer 1
        OutRing[OutPutter] = (Ch2*B)/10;
        OutPutter++;
        // Check if at end of ring buffer and reset if needed.
        if(OutPutter>11999)
        {
            OutPutter = 0;
        }
    }

	// Pole EP3 for command/data arrival
    EP3_PACKET_REC();    

}


 
 
 
 
 
 
 
 
 
 
 
 
 
  
